#include "devfs.h"
#include "dev.h"
#include "klib.h"
#include "log.h"

static devfs_type_t dev_type_table[] = {
    {
        .name      = "tty",
        .dev_type  = DEV_TTY,
        .file_type = FILE_TTY,
    },
};

int devfs_mount(struct _fs_t *fs, int major, int minor)
{
    fs->type = FS_DEVFS;
}
void devfs_umount(struct _fs_t *fs)
{
}
int path_to_num(const char *path, int *minor)
{
    if (path && *path >= '0' && *path <= '9')
    {
        int index = 0;
        while (path && *path >= '0' && *path <= '9')
        {
            index = index * 10 + *path - '0';
            path++;
        }
        *minor = index;
        return index;
    }
    return -1;
}
const char *path_next_child(const char *path)
{
    int len = kernel_strlen(path);
    while (len > 0 && *(path + len - 1) != '/')
    {
        len--;
    }
    return *(path + len - 1) == '/' ? (path + len) : (char *)0;
}
int devfs_open(struct _fs_t *fs, const char *path, file_t *file)
{
    // path tty0,tty1
    for (int i = 0; i < sizeof(dev_type_table) / sizeof(dev_type_table[0]); i++)
    {
        devfs_type_t *type          = dev_type_table + i;
        int           minor         = -1;
        int           type_name_len = kernel_strlen(type->name);
        if (kernel_strncmp(path, type->name, type_name_len) == 0)
        {
            if ((kernel_strlen(path) <= type_name_len) || (path_to_num(path + type_name_len, &minor) < 0))
            {
                log_printf("devfs devfs_open: get device num failed.%s", path);
                break;
            }
            int dev_id = dev_open(type->dev_type, minor, (void *)0);
            if (dev_id < 0)
            {
                log_printf("devfs devfs_open:opendev failed %s", path);
                break;
            }
            file->dev_id = dev_id;
            file->fs     = fs;
            file->pos    = 0;
            file->size   = 0;
            file->type   = type->file_type;
            return 0;
        }
    }
    return -1;
}
int devfs_read(char *buf, int size, file_t *file)
{
    return dev_read(file->dev_id, file->pos, buf, size);
}
int devfs_write(char *buf, int size, file_t *file)
{
    return dev_write(file->dev_id, file->pos, buf, size);
}
void devfs_close(file_t *file)
{
    dev_close(file->dev_id);
}
int devfs_seek(file_t *file, uint32_t offset, int dir)
{
    return -1;
}
int devfs_stat(file_t *file, struct stat *st)
{
    return -1;
}
int devfs_ioctl(file_t *file, int cmd, int arg0, int arg1)
{
    return dev_control(file->dev_id, cmd, arg0, arg1);
}

int devfs_opendir(struct _fs_t *fs, const char *name, DIR *dir)
{
    return -1;
}
int devfs_readdir(struct _fs_t *fs, DIR *dir, struct dirent *dirent)
{
    return -1;
}
int devfs_closedir(struct _fs_t *fs, DIR *dir)
{
    return -1;
}
int devfs_unlink(struct _fs_t *fs, const char *path)
{
    return -1;
}

fs_op_t devfs_op = {
    .mount  = devfs_mount,
    .umount = devfs_umount,
    .open   = devfs_open,
    .read   = devfs_read,
    .write  = devfs_write,
    .close  = devfs_close,
    .seek   = devfs_seek,
    .stat   = devfs_stat,
    .ioctl  = devfs_ioctl,

    .opendir  = devfs_opendir,
    .readdir  = devfs_readdir,
    .closedir = devfs_closedir,
    .unlink   = devfs_unlink,
};